package com.itheima.mp.demo;


import com.itheima.mp.util.MyUtil;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;

import java.lang.reflect.Method;

import static org.mockito.ArgumentMatchers.any;

@RunWith(PowerMockRunner.class)
@PrepareForTest({MyConstructorClass.class,PrivateObject.class,MyUtil.class,MyClass.class,
        MyStaticClass.class})
public class LastMockTwo {

    /*
    @PrepareForTest(PrivateObject.class)
    没有这个报这个错误
    org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Misplaced or misused argument matcher detected here:
     */
    @Test
//    @PrepareForTest(PrivateObject.class)
    public void testPrivateFieldAndMethod2() throws Exception {
        // 类实例（class instance）
        PrivateObject instance = new PrivateObject("kkk");
//        Method method = PowerMockito.method(PrivateObject.class, "getPrivateStringTwo", String.class);
//        Object say = Whitebox.invokeMethod(instance, "getPrivateStringTwo", "hi");
//        System.out.println(say);

        PrivateObject spy = PowerMockito.spy(instance);
        PowerMockito.when(spy, "getPrivateStringTwo", any()).thenReturn("mock private method return value");//私有方法mockito不行了，需要用无所不能的PowerMock监视spy

        Method check = PrivateObject.class.getDeclaredMethod("getPrivateStringTwo", String.class);
        check.setAccessible(true);
        Object result = check.invoke(spy, "aaa");
        System.out.println(result);
        Assert.assertEquals("mock private method return value",result);
    }


    @Test

    public void testPrivateFieldAndMethod3() throws Exception {
        // 类实例（class instance）
        PrivateObject instance = new PrivateObject("kkk");
//        Method method = PowerMockito.method(PrivateObject.class, "getPrivateStringTwo", String.class);
//        Object say = Whitebox.invokeMethod(instance, "getPrivateStringTwo", "hi");
//        System.out.println(say);

        PrivateObject spy = PowerMockito.spy(instance);
        PowerMockito.when(spy, "getPrivateString").thenReturn("mock private method return value");//私有方法mockito不行了，需要用无所不能的PowerMock监视spy

        Method check = PrivateObject.class.getDeclaredMethod("getPrivateString");
        check.setAccessible(true);
        Object result = check.invoke(spy);
        System.out.println(result);
        Assert.assertEquals("mock private method return value",result);
    }


    @Test
//    @PrepareForTest(value = {MyUtil.class})
    public void testHello() {
        PowerMockito.mockStatic(MyUtil.class);
        PowerMockito.when(MyUtil.hello()).thenReturn("hi");
        Assert.assertEquals("hi", MyUtil.hello());
    }

    /*
    有个问题虽然能运行成功但是不能显示覆盖率
    PowerMockito.spy 类需要放到
    @PrepareForTest({PrivateObject.class,MyUtil.class,MyClass.class})，否则不会生效
     */
    @Test
    public void testGetTotal() throws Exception {
        MyClass myClass = PowerMockito.spy(new MyClass());

        PowerMockito.doReturn(20).when(myClass, "getTotal");
        Object result = Whitebox.invokeMethod(myClass, "getTotal" );
        System.out.println(result);
        Assert.assertEquals(20, result);
    }

    @Test
    public void testGetTotalStaticMethod() throws Exception {
        PowerMockito.mockStatic(MyStaticClass.class);
        PowerMockito.when(MyStaticClass.getTotal()).thenReturn(20);

        Assert.assertEquals(20, MyStaticClass.getTotal());
    }


    @Test
    public void testConstructor() throws Exception {
        MyConstructorClass myConstructorClass = new MyConstructorClass(20);
        PowerMockito.whenNew(MyConstructorClass.class).withArguments(10)
                .thenReturn(myConstructorClass);

        /*
        org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here:
-> at com.itheima.mp.two.LastMockTwo.testConstructor(LastMockTwo.java:110)
         */
        //这样写会出现错误
//        PowerMockito.whenNew(MyConstructorClass.class).withArguments(10)
//         .thenReturn(new MyConstructorClass(20));

        MyConstructorClass mock = new MyConstructorClass(10);
        Assert.assertEquals(20, mock.getX());
    }

}